﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using blackhouse.BlackApart.Data;
using blackhouse.BlackApart.Actions.Log;
using System.Globalization;

namespace blackhouse.BlackApart.Actions {
	public class ActionRunner {

		#region Fields

		private IActionDataAccess dataAccess;
		private IActionLog log;
		private Action currentAction;
		private List<IActionLog> actionLogs = new List<IActionLog>();

		#endregion

		#region Constructors

		public ActionRunner(IActionDataAccess dataAccess, IActionLog log) {
			this.dataAccess = dataAccess;
			this.log = log;
			this.log.StartDate = DateTime.Now;
			this.log.EndDate = DateTime.MaxValue;
			this.log.Status = ActionStatus.Wait;
			this.log.Title = "Action Runner";
		}

		#endregion

		#region Methods

        public void MakeAutomaticStatusChange() {
            this.dataAccess.InvokeAutomaticStatusChange();
        }

        public void DeleteInterruptedReservations() {
            this.dataAccess.DeleteInterruptedReservations();
        }

		public bool GotoNextAction() {
			this.currentAction = this.GetTopAction();
			return this.currentAction != null;
		}

		public void RunAction() {
			this.log.Status = ActionStatus.Pending;
			IActionLog actionLog = this.log.AssignNewLogToAction(this.currentAction);
			this.actionLogs.Add(actionLog);
			actionLog.StartDate = DateTime.Now;
			actionLog.Status = ActionStatus.Pending;
			actionLog.Save();
			try {
				this.currentAction.Run();
				actionLog.EndDate = DateTime.Now;
				actionLog.Status = ActionStatus.Complete;
				actionLog.Save();
			}
			catch (Exception e) {
				actionLog.EndDate = DateTime.Now;
				actionLog.Status = ActionStatus.Error;
				actionLog.AppendToMessage(e.Message);
				actionLog.AppendToMessage(e.StackTrace);
				actionLog.Save();
				this.CurrentActionBringToActive();
			}
			this.log.EndDate = DateTime.Now;
			this.log.Status = ActionStatus.Complete;
			this.log.Save();
		}

		private void CurrentActionBringToActive() {
			this.dataAccess.MarkAsActive(this.currentAction.StockActionId);
		}

		private Action GetTopAction() {
			ActionData data = this.dataAccess.DequeueTopAction(CultureInfo.CurrentCulture.Name);
			if (string.IsNullOrEmpty(data.StockActionId))
				return null;
			return this.ConvertToAction(data);
		}

		private Action ConvertToAction(ActionData data) {
			Type t = Type.GetType(data.ClassDeclaration, false);
			if (t != null) {
				Action a = Activator.CreateInstance(t) as Action;
				if (a != null) {
					a.StockActionId = data.StockActionId;
					a.Initialize(data.InitializeData);
				}
				return a;
			}
			else
				return null;
		}

		public IActionLog[] GetAllLogs() {
			return this.actionLogs.ToArray();
		}

		#endregion

	}
}
